home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FishMarket 1.0
/
FishMarket v1.0.iso
/
fishies
/
301-325
/
disk_319
/
cnewssrc
/
cnews.src.lzh
/
relay
/
fileart.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-07-31
|
11KB
|
390 lines
/*
* fileart - file an article, given its temporary file name and its headers
*
* It may be desirable to, some day, prevent cross-postings across
* "universes", where a universe might be "alt" or "comp.news".
*
* There are three classes of newsgroup for the purposes of filing:
* "wanted" (in the active file and missing the "x" flag);
* "not wanted" ("x"ed in active, or not in active and not matched by sys
* file's subscription list for this machine), so ignore it; or
* "don't know it" (not in active and matched by subscription list,
* so file the article in junk once, iff there are no good groups).
* junk *must* be in the active file or it's an error (ST_DROPPED),
* but junk may have an "x" flag to prevent filing.
*
* Use the active file 'x' flag to snuff groups quietly, even when your
* subscription list permits them, without filing in junk.
*/
#ifdef DEBUG
# define STAT(x) { fprintf(stderr,"%s: %d, ",__FUNC__,__LINE__);\
fprintf x;\
fflush(stderr); }
#else
# define STAT(x)
#endif
#include <stdio.h>
#include <errno.h>
#ifndef AMIGA
# include <sys/types.h>
#endif /* AMIGA */
#include "libc.h"
#include "news.h"
#include "config.h"
#include "active.h"
#include "mkdirs.h"
#include "headers.h"
#include "article.h"
#include "history.h"
#include "system.h"
#define JUNK "junk" /* lost+found pseudo-ng. */
#define CONTROL "control" /* control message pseudo-ng. */
static long artnum; /* asgnartnum sets artnum */
static int goodngs; /* asgnartnum reads goodngs */
static boolean debug = NO;
/* imports from news */
extern void prefuse();
/* forwards */
FORWARD void asgnartnum(), gotgoodng(), mkjunklink(), mklinks();
FORWARD boolean openorlink(), mkonelink(), tryartnum();
void
filedebug(state) /* set debugging state */
boolean state;
{
debug = state;
}
/*
* File in the spool directory the article in art & fill in art->a_files.
* Generate Xref: header if needed (successfully cross-posted).
*
* If a_unlink is true, there is a temp file, so openfirst should
* be false, and vice versa.
*
* If openfirst (!art->a_unlink) is true, fill in a_tmpf with the name of
* the first link, fopen it (into art->a_artf), and make any remaining links.
* If openfirst is false, just make links to a_tmpf, which is already
* open as art->a_artf. openfirst means "Newsgroups:" was seen in time.
*/
void fileart(art)
register struct article *art;
{
register boolean openfirst = !art->a_unlink;
int junkgroups = 0; /* count "junked" groups */
char artnumstr[MAXCOMP]; /* article number in ascii */
if (art->a_filed)
return; /* don't file twice */
artnum = 0;
goodngs = 0;
STAT((stderr,"calling mklinks()\n"));
mklinks(art, openfirst, artnumstr, &junkgroups);
STAT((stderr,"calling mkjunklink()\n"));
mkjunklink(art, openfirst, artnumstr, &junkgroups);
STAT((stderr,"goodngs = %d\n", goodngs));
if (goodngs > 1 && art->a_artf != NULL) /* cross-posted? */
emitxref(art);
}
/*
* Store in spooldir. Link temp file to spooldir/ng/article-number
* for each ng. Control messages go in CONTROL, never in all.all.ctl.
*/
STATIC void mklinks(art, openfirst, artnumstr, junkgroupsp)
register struct article *art;
boolean openfirst;
char *artnumstr;
int *junkgroupsp;
{
register char *ngs, *ng;
register char *comma;
ngs = (art->h.h_ctlcmd != NULL? CONTROL: art->h.h_ngs);
if (art->a_status&ST_REFUSED)
(void) fprintf(stderr,
"%s: mklinks called with ST_REFUSED set (can't happen)\n",
progname);
for (; ngs != NULL; ngs = comma) {
comma = index(ngs, NGSEP);
if (comma != NULL)
*comma = '\0'; /* will be restored below */
STAT((stderr,"calling realngname()\n"));
ng = realngname(ngs);
STAT((stderr," returned '%s'\n", ng));
if (ng == NULL)
ng = strsave(ngs);
STAT((stderr,"calling asgnartnum()\n"));
asgnartnum(art, openfirst, ng, artnumstr);
/*
* If no such group in active or link failed, and the group
* wasn't 'x'ed in active, but our subscription list permits
* this group, then set flag to file it under "junk" later.
*/
if ((artnum < 1 || art->a_status != ST_OKAY) &&
art->a_status != ST_REFUSED &&
ngmatch(oursys()->sy_ngs, ng)) {
STAT((stderr,"artnum = %d, ST_OKAY %c, ST_REFUSED %c\n",
artnum,
art->a_status == ST_OKAY ? 'T' : 'F',
art->a_status == ST_REFUSED ? 'T' : 'F'));
++*junkgroupsp;
}
/*
* If article # was assigned & link succeeded,
* update art->a_files list for history.
*/
if (artnum >= 1 && art->a_status == ST_OKAY)
gotgoodng(art, ng, artnumstr);
free(ng);
if (comma != NULL)
*comma++ = NGSEP; /* step past comma */
/* asgnartnum refused just this ng */
art->a_status &= ~ST_REFUSED;
}
}
/*
* File once in "junk" iff no ngs were filed due to absence from
* active, but some were permitted by sys. This will make one junk
* link, no matter how many bad groups, and only if all are bad
* (e.g. rec.drugs,talk.chew-the-fat).
*/
STATIC void mkjunklink(art, openfirst, artnumstr, junkgroupsp)
register struct article *art;
boolean openfirst;
char *artnumstr;
int *junkgroupsp;
{
if (*junkgroupsp > 0 && goodngs == 0) { /* all groups were "junked"? */
asgnartnum(art, openfirst, JUNK, artnumstr);
if (artnum >= 1 && art->a_status == ST_OKAY) {
gotgoodng(art, JUNK, artnumstr);
art->a_status |= ST_JUNKED;
} else {
/*
* couldn't file article in junk.
* was JUNK not 'x'ed (i.e. doesn't exist)?
*/
if (art->a_status != ST_REFUSED) {
static boolean warned = NO;
art->a_status |= ST_REFUSED|ST_DROPPED;
if (!warned) {
warned = YES;
(void) fprintf(stderr,
"%s: no %s group\n", progname, JUNK);
}
}
prefuse(art);
(void) printf("no known groups in `%s' and no `%s' group\n",
art->h.h_ngs, JUNK);
}
} else if (goodngs == 0) {
extern boolean histreject;
/*
* Groups were permitted by subscription list, but all
* were 'x'ed in active, or otherwise refused.
*/
if (histreject)
history(art, NOLOG);
prefuse(art);
(void) printf("all groups `%s' excluded in active\n", art->h.h_ngs);
art->a_status |= ST_REFUSED;
}
}
/*
* Append ng/artnumstr to art's list of files, and bump goodngs.
*/
STATIC void gotgoodng(art, ng, artnumstr)
struct article *art;
char *ng, *artnumstr;
{
++goodngs;
histupdfiles(art, ng, artnumstr);
}
/*
* Assign a permanent name and article number to the temporary name
* art->a_tmpf in newsgroup "ng" & store the ascii form of the article
* number into "artnumstr", returning the article number in "artnum".
*
* If openfirst is true and goodngs is zero, set inname to artname,
* fopen artname and store the result in art->a_artf.
*/
STATIC void asgnartnum(art, openfirst, ng, artnumstr)
struct article *art;
boolean openfirst; /* open first link? */
register char *ng; /* read-only */
char *artnumstr;
{
register char *slashng; /* a group, slashed */
/* field active 'x' flag: don't file this group, quietly */
if (unwanted(ng)) {
STAT((stderr,"unwanted(`%s') returned TRUE\n", ng));
artnum = -1;
art->a_status |= ST_REFUSED;
return;
}
slashng = strsave(ng);
STAT((stderr,"calling mkfilenm(`%s')\n", slashng));
mkfilenm(slashng); /* relative to spooldir */
STAT((stderr,"calling nxtartnum(`%s')\n", ng));
while ((artnum = nxtartnum(ng)) >= 1) {
STAT((stderr,"nxtartnum(`%s') returned %d\n", ng, artnum));
if (tryartnum(art, openfirst, slashng, artnumstr))
break;
}
free(slashng);
}
/*
* Construct a link name (slashng/artnum) for this article,
* and try to link art to it.
*
* We changed directory to spooldir in main(), so the generated name
* is relative to spooldir, therefore artname can be used as is.
*
* Return value is identical to mkonelink's.
*/
STATIC boolean tryartnum(art, openfirst, slashng, artnumstr)
register struct article *art;
boolean openfirst;
register char *slashng;
char *artnumstr; /* side-effect returned here */
{
register char *artname; /* article file name */
register boolean ret;
(void) sprintf(artnumstr, "%ld", artnum);
artname = nemalloc((unsigned) (strlen(slashng) +
STRLEN(SFNDELIM) + strlen(artnumstr) + 1));
(void) strcpy(artname, slashng);
(void) strcat(artname, SFNDELIM);
(void) strcat(artname, artnumstr);
#ifdef notdef
char *tartname = strsave(artfile(artname));
free(artname);
artname = tartname;
#endif
STAT((stderr, "calling mkonelink(`%s')\n", artname));
ret = mkonelink(art, artname, openfirst);
free(artname);
return ret;
}
/*
* Try to link art to artname.
*
* If the attempt fails, maybe some intermediate directories are missing,
* so create any missing directories and try again. If the second attempt
* also fails, look at errno; if it is EEXIST, artname already exists
* (presumably because the active file is out of date, or the existing
* file is a directory such as net/micro/432), so indicate that higher
* levels should keep trying, otherwise we are unable to create the
* necessary directories, so complain and set bad status in art.
*
* Returns YES iff there is no point in trying to file this article again,
* usually because it has been successfully filed, but sometimes because
* the necessary directories cannot be made.
*/
STATIC boolean mkonelink(art, artname, openfirst)
register struct article *art;
register char *artname;
boolean openfirst;
{
if (openorlink(artname, art, openfirst, goodngs))
return YES;
else {
STAT((stderr, "openorlink() failed\n"));
STAT((stderr, "calling mkdirs(`%s')\n", artname));
(void) mkdirs(artname, getuid(), getgid());
STAT((stderr, "trying openorlink() again\n"));
if (openorlink(artname, art, openfirst, goodngs))
return YES;
else if (errno != EEXIST) {
warning("can't link to `%s'", artname);
art->a_status |= ST_DROPPED;
return YES; /* hopeless - give up */
} else
return NO;
}
}
/*
* Try to make a link of art (actually art->a_tmpf) to artname.
* If no links have been made yet, record and open artname iff no
* link yet exists to that name (by any file, to avoid overwriting
* existing articles, e.g. due to an out-of-date active file).
* If links already exist, try to make artname a link to the first link
* (art->a_tmpf).
*
* Liberally sprinkled with debugging output, as this is the heart
* of article filing.
*/
STATIC boolean openorlink(artname, art, openfirst, goodngcnt)
register char *artname;
register struct article *art;
boolean openfirst; /* open art's first link? */
int goodngcnt; /* count of good news groups */
{
register boolean worked; /* open or link worked? */
if (openfirst && goodngcnt == 0) {
if (debug)
(void) fprintf(stderr, "opening `%s'... ", artname);
nnfree(&art->a_tmpf);
art->a_tmpf = strsave(artname);
art->a_artf = fopenexcl(art->a_tmpf);
worked = art->a_artf != NULL;
} else {
if (debug)
(void) fprintf(stderr, "linking `%s' to `%s'... ",
art->a_tmpf, artname);
worked = link(art->a_tmpf, artname) == 0;
if (!worked)
/*
* If art->a_tmpf really *is* a temporary name (because
* the whole header didn't fit in core), then this will
* produce a symbolic link to a non-existent name when
* art->a_tmpf is unlinked, which will be soon.
* Moral: don't run Eunice on your PDP-11.
*/
worked = symlink(art->a_tmpf, artname) == 0;
}
if (debug)
if (worked)
(void) fprintf(stderr, "success.\n");
else
warning("failed.", "");
return worked;
}